package com.hxz.graduationdesign.util;

import com.hxz.graduationdesign.pojo.dto.UpVideoDto;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import io.github.bonigarcia.wdm.WebDriverManager;


import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class BilibiliUpVideoCrawler {

    public static List<UpVideoDto> getUpVideo(String uid) {

//        System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver-win64/chromedriver.exe");
        // 因为chrome会自动更新，没想到它不用魔法就会自动更新，所有不再使用本地下载的使用ChromeDriver
        // WebDriverManager 自动下载并配置 ChromeDriver
        WebDriverManager.chromedriver().setup();

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36");
        options.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"));
        options.addArguments("--disable-blink-features=AutomationControlled");
        options.addArguments("--disable-gpu");
        options.addArguments("--no-sandbox");
        options.addArguments("--remote-allow-origins=*");
        options.addArguments("--disable-web-security");
        options.addArguments("--ignore-certificate-errors");
        options.setExperimentalOption("useAutomationExtension", false);
        options.addArguments("--headless");

        WebDriver driver = new ChromeDriver(options);
        driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);

        List<UpVideoDto> upVideoList = new ArrayList<>();

        try {
            driver.manage().window().maximize();

            // 这个有时候需要手动更新
            driver.get("https://www.bilibili.com");
            driver.manage().addCookie(new Cookie("SESSDATA", "3533ab04%2C1760165697%2Cd9572%2A41CjC4GyVWoP3QwcZYai9Eugq66IIiZUVavXZQ-J3E_aWRmFatBkChePndsVKAhGWXvvcSVkJfTWRrOU44X0d0N3B0RC0zaGQ2YzI0eDBCQnJhN2Flem9ieVRnVUZ4SGZQR251MTh2d3NOdUd2dHFVZE84MVNBZXhvbDJOZVdINzJ4VTNzUURhdm1nIIEC",
                    ".bilibili.com", "/", null));
            driver.manage().addCookie(new Cookie("bili_jct", "cc7c196ff8fcd88bc68b76949ad4ec39",
                    ".bilibili.com", "/", null));
            driver.manage().addCookie(new Cookie("sid", "7sdhrhoc",
                    ".bilibili.com", "/", null));
            driver.navigate().refresh();

            int sum = 0;
            String upHomeUrl = "https://space.bilibili.com/" + uid + "/video";
            driver.get(upHomeUrl);

            WebDriverWait wait = new WebDriverWait(driver, 50);
            int maxPageAttempts = 500;
            int currentPage = 1;
            boolean hasNextPage = true;

            while (hasNextPage && currentPage <= maxPageAttempts) {
                wait.until(ExpectedConditions.presenceOfElementLocated(
                        By.cssSelector("div.upload-video-card")
                ));

                scrollToBottom(driver);

                List<WebElement> videos = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(
                        By.cssSelector("div.upload-video-card")
                ));
                upVideoList.addAll(processVideos(videos,uid));
                sum += videos.size();

                try {
                    // 分页处理
                    WebElement pagination = wait.until(ExpectedConditions.presenceOfElementLocated(
                            By.cssSelector(".video-pagination")
                    ));

                    // 定位可用的下一页按钮
                    List<WebElement> nextButtons = driver.findElements(
                            By.cssSelector("button.vui_pagenation--btn-side:not(.vui_button--disabled)")
                    );

                    if (!nextButtons.isEmpty()) {
                        WebElement nextPageButton = nextButtons.get(nextButtons.size() - 1);

                        // 滚动到分页区域
                        ((JavascriptExecutor) driver).executeScript(
                                "arguments[0].scrollIntoView({behavior: 'smooth', block: 'center'});",
                                pagination
                        );

                        // 确保按钮可点击
                        wait.until(ExpectedConditions.elementToBeClickable(nextPageButton));

                        // 使用JS点击确保触发
                        ((JavascriptExecutor) driver).executeScript("arguments[0].click();", nextPageButton);

                        // 等待页码更新
                        wait.until(ExpectedConditions.textToBe(
                                By.cssSelector("button.vui_button--active-blue.vui_pagenation--btn-num"),
                                String.valueOf(currentPage + 1)
                        ));

                        currentPage++;
//                        System.out.println("成功跳转到第" + currentPage + "页");
                    } else {
//                        System.out.println("没有可用的下一页按钮，停止翻页");
                        //好像会跳到倒数第二页一次，但好像也没啥影响
                        hasNextPage = false;
                    }
                } catch (TimeoutException e) {
//                    System.out.println("等待分页元素超时，可能已到最后一页");
                    hasNextPage = false;
                } catch (Exception e) {
                    System.err.println("翻页异常: " + e.getMessage());
                    e.printStackTrace();
//                    savePageSource(driver, "page_error_" + currentPage + ".html");
                    hasNextPage = false;
                }
            }

//            System.out.println("最终爬取总数: " + sum);

        } catch (Exception e) {
            System.err.println("主流程异常:");
            e.printStackTrace();
//            savePageSource(driver, "error.html");
        } finally {
            driver.quit();
        }

        return upVideoList;
    }

    private static List<UpVideoDto> processVideos(List<WebElement> videos,String uid) {
        List<UpVideoDto> upVideoList = new ArrayList<>();
        for (WebElement video : videos) {
            try {
                String title = video.findElement(By.cssSelector(".bili-video-card__title")).getText();
                String url = video.findElement(By.cssSelector("a.bili-cover-card")).getAttribute("href");

                List<WebElement> stats = video.findElements(By.cssSelector(".bili-cover-card__stat"));
                String playCount = stats.size() > 0 ? stats.get(0).getText() : "N/A";
                String danmuCount = stats.size() > 1 ? stats.get(1).getText() : "N/A";
                String duration = stats.size() > 2 ? stats.get(2).getText() : "N/A";

                String uploadDate = video.findElement(By.cssSelector(".bili-video-card__subtitle span")).getText();

                Integer playCountNum = FormattingTool.parseNumber(playCount);
                Integer danmuCountNum = FormattingTool.parseNumber(danmuCount);
                String bv = FormattingTool.getBv(url);
//                Integer durationNum = convertToSeconds(duration);
                Date upDate = FormattingTool.parseDate(uploadDate);

                UpVideoDto upVideoDto = new UpVideoDto();
                upVideoDto.setBv(bv);
                upVideoDto.setTitle(title);
                upVideoDto.setUid(uid);
                upVideoDto.setPlayCount(playCountNum);
                upVideoDto.setDamuCount(danmuCountNum);
                upVideoDto.setDuration(duration);
                upVideoDto.setUploadTime(upDate);

                upVideoList.add(upVideoDto);

//                System.out.println("标题: " + title);
//                System.out.println("bv号: " + bv);
//                System.out.println("播放量: " + playCountNum + " | 弹幕量: " + danmuCountNum);
//                System.out.println("时长: " + duration + " | 日期: " + upDate);
//                System.out.println("----------------------");
            } catch (StaleElementReferenceException e) {
                System.err.println("元素已过期，跳过该视频");
            } catch (Exception e) {
                System.err.println("视频处理异常: " + e.getMessage());
            }
        }
        return upVideoList;
    }

    private static void scrollToBottom(WebDriver driver) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        long lastHeight = (long) js.executeScript("return document.documentElement.scrollHeight");
        int scrollAttempts = 0;

        while (scrollAttempts < 5) {
            js.executeScript("window.scrollTo(0, document.documentElement.scrollHeight);");
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long newHeight = (long) js.executeScript("return document.documentElement.scrollHeight");
            if (newHeight == lastHeight) break;
            lastHeight = newHeight;
            scrollAttempts++;
        }
    }

    private static void savePageSource(WebDriver driver, String filename) {
        try {
            Files.write(Paths.get(filename), driver.getPageSource().getBytes());
            System.out.println("已保存错误页面到: " + filename);
        } catch (IOException e) {
            System.err.println("保存页面失败: " + e.getMessage());
        }
    }
}
